#include "TcpServer.h"
#include "Logger.h"


#include <cstring>


static EventLoop* CheckLoopNotNUll(EventLoop* loop)
{
    if (loop == nullptr) {
        LOG_FATAL("mainloop is null...... \n");
    }

    return loop;
}

TcpServer::TcpServer(EventLoop *loop, const InetAddress &listenAddr, const std::string &nameArg, Option option)
    : m_loop(CheckLoopNotNUll(loop))
    , m_ipPort(listenAddr.toIpPort()) 
    , m_name(nameArg)
    , m_acceptor(new Acceptor(loop, listenAddr, option == kReusePort))
    , m_threadPool(new EventLoopThreadPool(loop, m_name))
    , m_connectionCallback()
    , m_messageCallback()
    , m_nextConnId(1)
    , m_started(0)
{
    // 当有新用户连接时，会执行TcpServer::newConnection回调
    m_acceptor->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this, 
                                         std::placeholders::_1, std::placeholders::_2 ));
}

TcpServer::~TcpServer()
{
    for (auto& item : m_connections) {
        // conn局部智能指针对象出出括号时，会自动调用new出来的TcpConnection的资源
        TcpConnectionPtr conn(item.second);
        item.second.reset();

        conn->getLoop()->runInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
    }
}

// 设置底层subloop的个数
void TcpServer::setThreadNum(int numThreads)
{
    m_threadPool->setThreadNum(numThreads);
}

// 开启服务器进行监听
void TcpServer::start()
{
    if (m_started ++ == 0) { // 防止一个TcpServer被启动多次
        m_threadPool->start(m_threadInitCallback); // 启动底层的loop线程池
        m_loop->runInLoop(std::bind(&Acceptor::listen, m_acceptor.get()));
    }
}

// 有新的客户端连接时，Acceptor会接受连接，执行回调操作
void TcpServer::newConnection(int sockfd, const InetAddress &peerAddr)
{
    // 通过轮询算法选择一个线程的loop, Acceptor会执行这个回调操作
    EventLoop* ioLoop = m_threadPool->getNextLoop();
    char buf[64] = {0};
    snprintf(buf, sizeof(buf), "-%s#%d", m_ipPort.c_str(), m_nextConnId);
    ++ m_nextConnId;
    std::string connName = m_name + buf;

    LOG_INFO("TcpServer::newConnection [%s] - new connection [%s] from %s \n", m_name.c_str(), 
                                                connName.c_str(), peerAddr.toIpPort().c_str());

    // 通过sockfd获取其绑定的本机的ip地址和端口信息
    sockaddr_in local;
    memset(&local, 0, sizeof(local));    
    socklen_t addrlen = sizeof local;
    if (::getsockname(sockfd, (sockaddr*)&local, &addrlen) < 0) {
        LOG_ERROR("sockets::getLocalAddr");
    }
    InetAddress localAddr(local);     

    // 根据连接建立成功的sockfd创建TcpConnection连接对象
    TcpConnectionPtr conn(new TcpConnection(ioLoop, connName,
                            sockfd,   // Socket Channel
                            localAddr, peerAddr)
                        );          

    m_connections[connName] = conn;
    // 下面的回调都是用户设置给 TcpServer => TcpConnection => Channel => Poller => 通知channel调用回调
    conn->setConnectionCallback(m_connectionCallback);
    conn->setMessageCallback(m_messageCallback);
    conn->setWriteCompleteCallback(m_writeCompleteCallback);

    // 设置了如何关闭连接的回调   conn->shutDown()
    conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1));

    // 直接调用TcpConnection::connectEstablished 建立连接并注册EPOLLIN事件
    ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));                                                     
}

void TcpServer::removeConnection(const TcpConnectionPtr &conn)
{
    m_loop->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
}

void TcpServer::removeConnectionInLoop(const TcpConnectionPtr &conn)
{
    LOG_INFO("TcpServer::removeConnectionInLoop [%s] - connection %s\n", m_name.c_str(), conn->name().c_str());

    m_connections.erase(conn->name());
    EventLoop *ioLoop = conn->getLoop(); 
    ioLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
}
